﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Simulated_Annealing
{

     
    public class SimA
    {

            public static double T_k;
            public static double theta;
            public static double beta_k;
            public static double T_s;
            public static double T_f;
            public static double alpha;
            public static double gamma;
            public static double T_b;
            public static double T_r;
            public static int R;
            public static int Nfeas;
            public static int k;    //this is the iteration count

          public static void Initialize(int network_nodes, int Numfeas, VRP network, Random random)
        {
            List<double> initialtemps = new List<double>();
            initialtemps = VRP.find_temp(network, random);
            T_f = initialtemps[0];
            T_s = initialtemps[1];
            T_r = T_s;                  //Set equal to T_s initially: correct
            T_k = T_s;                  //make the beginning temperature equal to the starting temperature : correct
            gamma = network_nodes;      //according to paper
            Nfeas = Numfeas;                //according to paper
            alpha = network_nodes * Nfeas; //according to paper
            beta_k = 2;  //set equal to whatever
            R = 0;
            k = 0;
        }

        //takes in the delta value and the nubmer of route pairs that it could go through, 
        //and the current number of rejected row pairs
        public static int Run(double delta, int imax, int counter)    
        {


            k= k+1;   //we pass the counter for the interation
            int kmax = imax;   //the size of the route list...we will use this to check how to update the temperature
            int acceptCheck; // 0 if we reject, 1 if we accept

            double delta_cost = delta;
         
            double ratio = delta_cost/T_k;
  

            double e = Math.E;  
            double power_ratio = Math.Pow(e,-ratio);


            //perform simulated annealing

            //generate theta:
            Random random = new Random();

            double theta = random.NextDouble();  //returns a number between 0 and 1

            //check to see if you accept  ( I did the negative of delta from program so that it is the same as the algorithm
            if (delta_cost <= 0 || (delta_cost > 0 && power_ratio >= theta))  //acceptance criteria
            {
                //we accept!
                acceptCheck = 1;

            }
            else  //we want to update the temperatue differently
            {
                 //we reject!
                acceptCheck = 0;  

            }

            //update the temperatue
            if (counter == kmax-1)  //use occasional increment rule to reset the temperautre, since this means we went through all route pairs and didn't find any to accept
            {

                if (T_r / 2 < T_b)   //find the max of these two
                {
                    T_r = T_b;    //update T_r
                }
                else
                {
                    T_r = T_r / 2;   //update T_r
                }
                T_k=T_r;              //update T_k

            }
            else   //then we use the normal decrement rule
            { 
                double kdouble= k;   //we need k to be a double here to use in beta_k computation
                
                beta_k = (T_s - T_f) / ((alpha + gamma * Math.Sqrt(k)) * T_s * T_f);  //update beta_k

                T_k = T_k / (1 + beta_k * T_k);  //update T_k

            }


            //if the system freezes, we go back to the main program to increment R, otherwise we pass the current solution back to Neighborhood
            
            if(T_k < T_f) //system has frozen
            {
                R = R + 1;   //update the Reset clock
                T_k = T_r;  
            }

            return acceptCheck;
        }


    }
}
